Package org.pushingpixels.flamingo.api.common

Source Code of org.pushingpixels.flamingo.api.common.AbstractCommandButton$ActionHandler

/*
* Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  o Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*    
*  o Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*    
*  o Neither the name of Flamingo Kirill Grouchnikov nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*    
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.flamingo.api.common;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.*;

import javax.accessibility.AccessibleContext;
import javax.swing.ButtonModel;
import javax.swing.SwingConstants;
import javax.swing.event.*;

import org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
import org.pushingpixels.flamingo.api.common.model.ActionButtonModel;
import org.pushingpixels.flamingo.internal.ui.common.CommandButtonUI;

/**
* Base class for command buttons.
*
* @author Kirill Grouchnikov
*/
public abstract class AbstractCommandButton extends
    RichToolTipManager.JTrackableComponent {
  /**
   * Associated icon.
   *
   * @see #setIcon(ResizableIcon)
   * @see #getIcon()
   */
  protected ResizableIcon icon;

  /**
   * Associated disabled icon.
   *
   * @see #setDisabledIcon(ResizableIcon)
   * @see #getDisabledIcon()
   */
  protected ResizableIcon disabledIcon;

  /**
   * The button text.
   *
   * @see #setText(String)
   * @see #getText()
   */
  private String text;

  /**
   * The button action model.
   *
   * @see #getActionModel()
   * @see #setActionModel(ActionButtonModel)
   */
  protected ActionButtonModel actionModel;

  /**
   * Additional text. This is shown for {@link CommandButtonDisplayState#TILE}
   * .
   *
   * @see #setExtraText(String)
   * @see #getExtraText()
   */
  protected String extraText;

  /**
   * Current display state of <code>this</code> button.
   *
   * @see #setDisplayState(CommandButtonDisplayState)
   * @see #getDisplayState()
   */
  protected CommandButtonDisplayState displayState;

  /**
   * The dimension of the icon of the associated command button in the
   * {@link CommandButtonDisplayState#FIT_TO_ICON} state.
   *
   * @see #getCustomDimension()
   * @see #updateCustomDimension(int)
   */
  protected int customDimension;

  /**
   * Indication whether this button is flat.
   *
   * @see #setFlat(boolean)
   * @see #isFlat()
   */
  protected boolean isFlat;

  /**
   * Horizontal alignment of the content.
   *
   * @see #setHorizontalAlignment(int)
   * @see #getHorizontalAlignment()
   */
  private int horizontalAlignment;

  /**
   * Scale factor for horizontal gaps.
   *
   * @see #setHGapScaleFactor(double)
   * @see #getHGapScaleFactor()
   */
  private double hgapScaleFactor;

  /**
   * Scale factor for vertical gaps.
   *
   * @see #setVGapScaleFactor(double)
   * @see #getVGapScaleFactor()
   */
  private double vgapScaleFactor;

  /**
   * Rich tooltip for the action area.
   *
   * @see #setActionRichTooltip(RichTooltip)
   * @see #getRichTooltip(MouseEvent)
   */
  private RichTooltip actionRichTooltip;

  /**
   * Location order kind for buttons placed in command button strips or for
   * buttons that need the visuals of segmented strips.
   *
   * @see #setLocationOrderKind(CommandButtonLocationOrderKind)
   * @see #getLocationOrderKind()
   */
  private CommandButtonLocationOrderKind locationOrderKind;

  /**
   * Action handler for the button.
   */
  protected ActionHandler actionHandler;

  /**
   * Key tip for the action area.
   *
   * @see #setActionKeyTip(String)
   * @see #getActionKeyTip()
   */
  protected String actionKeyTip;

  /**
   * Enumerates the available values for the location order kind. This is used
   * for buttons placed in command button strips or for buttons that need the
   * visuals of segmented strips.
   *
   * @author Kirill Grouchnikov
   */
  public static enum CommandButtonLocationOrderKind {
    /**
     * Indicates that this button is the only button in the strip.
     */
    ONLY,

    /**
     * Indicates that this button is the first button in the strip.
     */
    FIRST,

    /**
     * Indicates that this button is in the middle of the strip.
     */
    MIDDLE,

    /**
     * Indicates that this button is the last button in the strip.
     */
    LAST
  }

  /**
   * Creates a new command button.
   *
   * @param text
   *            Button title. May contain any number of words.
   * @param icon
   *            Button icon.
   */
  public AbstractCommandButton(String text, ResizableIcon icon) {
    this.icon = icon;
    this.customDimension = -1;
    this.displayState = CommandButtonDisplayState.FIT_TO_ICON;
    this.horizontalAlignment = SwingConstants.CENTER;
    this.actionHandler = new ActionHandler();
    this.isFlat = true;
    this.hgapScaleFactor = 1.0;
    this.vgapScaleFactor = 1.0;
    this.setText(text);
    this.setOpaque(false);
  }

  /**
   * Sets the new UI delegate.
   *
   * @param ui
   *            New UI delegate.
   */
  public void setUI(CommandButtonUI ui) {
    super.setUI(ui);
  }

  /**
   * Returns the UI delegate for this button.
   *
   * @return The UI delegate for this button.
   */
  public CommandButtonUI getUI() {
    return (CommandButtonUI) ui;
  }

  /**
   * Sets new display state for <code>this</code> button. Fires a
   * <code>displayState</code> property change event.
   *
   * @param state
   *            New display state.
   * @see #getDisplayState()
   */
  public void setDisplayState(CommandButtonDisplayState state) {
    CommandButtonDisplayState old = this.displayState;
    this.displayState = state;

    this.firePropertyChange("displayState", old, this.displayState);
  }

  /**
   * Returns the associated icon.
   *
   * @return The associated icon.
   * @see #getDisabledIcon()
   * @see #setIcon(ResizableIcon)
   */
  public ResizableIcon getIcon() {
    return icon;
  }

  /**
   * Sets new icon for this button. Fires an <code>icon</code> property change
   * event.
   *
   * @param defaultIcon
   *            New default icon for this button.
   * @see #setDisabledIcon(ResizableIcon)
   * @see #getIcon()
   */
  public void setIcon(ResizableIcon defaultIcon) {
    ResizableIcon oldValue = this.icon;
    this.icon = defaultIcon;

    firePropertyChange("icon", oldValue, defaultIcon);
    if (defaultIcon != oldValue) {
      if (defaultIcon == null || oldValue == null
          || defaultIcon.getIconWidth() != oldValue.getIconWidth()
          || defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
        revalidate();
      }
      repaint();
    }
  }

  /**
   * Sets the disabled icon for this button.
   *
   * @param disabledIcon
   *            Disabled icon for this button.
   * @see #setIcon(ResizableIcon)
   * @see #getDisabledIcon()
   */
  public void setDisabledIcon(ResizableIcon disabledIcon) {
    this.disabledIcon = disabledIcon;
  }

  /**
   * Returns the associated disabled icon.
   *
   * @return The associated disabled icon.
   * @see #setDisabledIcon(ResizableIcon)
   * @see #getIcon()
   */
  public ResizableIcon getDisabledIcon() {
    return disabledIcon;
  }

  /**
   * Return the current display state of <code>this</code> button.
   *
   * @return The current display state of <code>this</code> button.
   * @see #setDisplayState(CommandButtonDisplayState)
   */
  public CommandButtonDisplayState getDisplayState() {
    return displayState;
  }

  /**
   * Returns the extra text of this button.
   *
   * @return Extra text of this button.
   * @see #setExtraText(String)
   */
  public String getExtraText() {
    return this.extraText;
  }

  /**
   * Sets the extra text for this button. Fires an <code>extraText</code>
   * property change event.
   *
   * @param extraText
   *            Extra text for this button.
   * @see #getExtraText()
   */
  public void setExtraText(String extraText) {
    String oldValue = this.extraText;
    this.extraText = extraText;
    firePropertyChange("extraText", oldValue, extraText);

    if (accessibleContext != null) {
      accessibleContext.firePropertyChange(
          AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
          oldValue, extraText);
    }
    if (extraText == null || oldValue == null
        || !extraText.equals(oldValue)) {
      revalidate();
      repaint();
    }
  }

  /**
   * Returns the text of this button.
   *
   * @return The text of this button.
   * @see #setText(String)
   */
  public String getText() {
    return this.text;
  }

  /**
   * Sets the new text for this button. Fires a <code>text</code> property
   * change event.
   *
   * @param text
   *            The new text for this button.
   * @see #getText()
   */
  public void setText(String text) {
    String oldValue = this.text;
    this.text = text;
    firePropertyChange("text", oldValue, text);

    if (accessibleContext != null) {
      accessibleContext.firePropertyChange(
          AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
          oldValue, text);
    }
    if (text == null || oldValue == null || !text.equals(oldValue)) {
      revalidate();
      repaint();
    }
  }

  /**
   * Updates the dimension of the icon of the associated command button in the
   * {@link CommandButtonDisplayState#FIT_TO_ICON} state. Fires a
   * <code>customDimension</code> property change event.
   *
   * @param dimension
   *            New dimension of the icon of the associated command button in
   *            the {@link CommandButtonDisplayState#FIT_TO_ICON} state.
   * @see #getCustomDimension()
   */
  public void updateCustomDimension(int dimension) {
    if (this.customDimension != dimension) {
      int old = this.customDimension;
      this.customDimension = dimension;
      this.firePropertyChange("customDimension", old,
          this.customDimension);
    }
  }

  /**
   * Returns the dimension of the icon of the associated command button in the
   * {@link CommandButtonDisplayState#FIT_TO_ICON} state.
   *
   * @return The dimension of the icon of the associated command button in the
   *         {@link CommandButtonDisplayState#FIT_TO_ICON} state.
   * @see #updateCustomDimension(int)
   */
  public int getCustomDimension() {
    return this.customDimension;
  }

  /**
   * Returns indication whether this button has flat appearance.
   *
   * @return <code>true</code> if this button has flat appearance,
   *         <code>false</code> otherwise.
   * @see #setFlat(boolean)
   */
  public boolean isFlat() {
    return this.isFlat;
  }

  /**
   * Sets the flat appearance of this button. Fires a <code>flat</code>
   * property change event.
   *
   * @param isFlat
   *            If <code>true</code>, this button will have flat appearance,
   *            otherwise this button will not have flat appearance.
   * @see #isFlat()
   */
  public void setFlat(boolean isFlat) {
    boolean old = this.isFlat;
    this.isFlat = isFlat;
    if (old != this.isFlat) {
      this.firePropertyChange("flat", old, this.isFlat);
    }

    if (old != isFlat) {
      repaint();
    }
  }

  /**
   * Returns the action model for this button.
   *
   * @return The action model for this button.
   * @see #setActionModel(ActionButtonModel)
   */
  public ActionButtonModel getActionModel() {
    return this.actionModel;
  }

  /**
   * Sets the new action model for this button. Fires an
   * <code>actionModel</code> property change event.
   *
   * @param newModel
   *            The new action model for this button.
   * @see #getActionModel()
   */
  public void setActionModel(ActionButtonModel newModel) {
    ButtonModel oldModel = getActionModel();

    if (oldModel != null) {
      oldModel.removeChangeListener(this.actionHandler);
      oldModel.removeActionListener(this.actionHandler);
    }

    actionModel = newModel;

    if (newModel != null) {
      newModel.addChangeListener(this.actionHandler);
      newModel.addActionListener(this.actionHandler);
    }

    firePropertyChange("actionModel", oldModel, newModel);
    if (newModel != oldModel) {
      revalidate();
      repaint();
    }
  }

  /**
   * Adds the specified action listener to this button.
   *
   * @param l
   *            Action listener to add.
   * @see #removeActionListener(ActionListener)
   */
  public void addActionListener(ActionListener l) {
    this.listenerList.add(ActionListener.class, l);
  }

  /**
   * Removes the specified action listener from this button.
   *
   * @param l
   *            Action listener to remove.
   * @see #addActionListener(ActionListener)
   */
  public void removeActionListener(ActionListener l) {
    this.listenerList.remove(ActionListener.class, l);
  }

  /**
   * Adds the specified change listener to this button.
   *
   * @param l
   *            Change listener to add.
   * @see #removeChangeListener(ChangeListener)
   */
  public void addChangeListener(ChangeListener l) {
    this.listenerList.add(ChangeListener.class, l);
  }

  /**
   * Removes the specified change listener from this button.
   *
   * @param l
   *            Change listener to remove.
   * @see #addChangeListener(ChangeListener)
   */
  public void removeChangeListener(ChangeListener l) {
    this.listenerList.remove(ChangeListener.class, l);
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.JComponent#setEnabled(boolean)
   */
  @Override
  public void setEnabled(boolean b) {
    if (!b && actionModel.isRollover()) {
      actionModel.setRollover(false);
    }
    super.setEnabled(b);
    actionModel.setEnabled(b);
  }

  /**
   * Default action handler for this button.
   *
   * @author Kirill Grouchnikov
   */
  class ActionHandler implements ActionListener, ChangeListener {
    public void stateChanged(ChangeEvent e) {
      fireStateChanged();
      repaint();
    }

    public void actionPerformed(ActionEvent event) {
      fireActionPerformed(event);
    }
  }

  /**
   * Notifies all listeners that have registered interest for notification on
   * this event type. The event instance is lazily created.
   *
   * @see EventListenerList
   */
  protected void fireStateChanged() {
    // Guaranteed to return a non-null array
    Object[] listeners = listenerList.getListenerList();
    // Process the listeners last to first, notifying
    // those that are interested in this event
    ChangeEvent ce = new ChangeEvent(this);
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
      if (listeners[i] == ChangeListener.class) {
        // Lazily create the event:
        ((ChangeListener) listeners[i + 1]).stateChanged(ce);
      }
    }
  }

  /**
   * Notifies all listeners that have registered interest for notification on
   * this event type. The event instance is lazily created using the
   * <code>event</code> parameter.
   *
   * @param event
   *            the <code>ActionEvent</code> object
   * @see EventListenerList
   */
  protected void fireActionPerformed(ActionEvent event) {
    // Guaranteed to return a non-null array
    Object[] listeners = listenerList.getListenerList();
    ActionEvent e = null;
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
      if (listeners[i] == ActionListener.class) {
        // Lazily create the event:
        if (e == null) {
          String actionCommand = event.getActionCommand();
          e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
              actionCommand, event.getWhen(), event
                  .getModifiers());
        }
        ((ActionListener) listeners[i + 1]).actionPerformed(e);
      }
    }
  }

  /**
   * Sets new horizontal alignment for the content of this button. Fires a
   * <code>horizontalAlignment</code> property change event.
   *
   * @param alignment
   *            New horizontal alignment for the content of this button.
   * @see #getHorizontalAlignment()
   */
  public void setHorizontalAlignment(int alignment) {
    if (alignment == this.horizontalAlignment)
      return;
    int oldValue = this.horizontalAlignment;
    this.horizontalAlignment = alignment;
    firePropertyChange("horizontalAlignment", oldValue,
        this.horizontalAlignment);
    repaint();
  }

  /**
   * Returns the horizontal alignment for the content of this button.
   *
   * @return The horizontal alignment for the content of this button.
   * @see #setHorizontalAlignment(int)
   */
  public int getHorizontalAlignment() {
    return this.horizontalAlignment;
  }

  /**
   * Sets new horizontal gap scale factor for the content of this button.
   * Fires an <code>hgapScaleFactor</code> property change event.
   *
   * @param hgapScaleFactor
   *            New horizontal gap scale factor for the content of this
   *            button.
   * @see #getHGapScaleFactor()
   * @see #setVGapScaleFactor(double)
   * @see #setGapScaleFactor(double)
   */
  public void setHGapScaleFactor(double hgapScaleFactor) {
    if (hgapScaleFactor == this.hgapScaleFactor)
      return;
    double oldValue = this.hgapScaleFactor;
    this.hgapScaleFactor = hgapScaleFactor;
    firePropertyChange("hgapScaleFactor", oldValue, this.hgapScaleFactor);
    if (this.hgapScaleFactor != oldValue) {
      revalidate();
      repaint();
    }
  }

  /**
   * Sets new vertical gap scale factor for the content of this button. Fires
   * a <code>vgapScaleFactor</code> property change event.
   *
   * @param vgapScaleFactor
   *            New vertical gap scale factor for the content of this button.
   * @see #getVGapScaleFactor()
   * @see #setHGapScaleFactor(double)
   * @see #setGapScaleFactor(double)
   */
  public void setVGapScaleFactor(double vgapScaleFactor) {
    if (vgapScaleFactor == this.vgapScaleFactor)
      return;
    double oldValue = this.vgapScaleFactor;
    this.vgapScaleFactor = vgapScaleFactor;
    firePropertyChange("vgapScaleFactor", oldValue, this.vgapScaleFactor);
    if (this.vgapScaleFactor != oldValue) {
      revalidate();
      repaint();
    }
  }

  /**
   * Sets new gap scale factor for the content of this button.
   *
   * @param gapScaleFactor
   *            New gap scale factor for the content of this button.
   * @see #getHGapScaleFactor()
   * @see #getVGapScaleFactor()
   */
  public void setGapScaleFactor(double gapScaleFactor) {
    setHGapScaleFactor(gapScaleFactor);
    setVGapScaleFactor(gapScaleFactor);
  }

  /**
   * Returns the horizontal gap scale factor for the content of this button.
   *
   * @return The horizontal gap scale factor for the content of this button.
   * @see #setHGapScaleFactor(double)
   * @see #setGapScaleFactor(double)
   * @see #getVGapScaleFactor()
   */
  public double getHGapScaleFactor() {
    return this.hgapScaleFactor;
  }

  /**
   * Returns the vertical gap scale factor for the content of this button.
   *
   * @return The vertical gap scale factor for the content of this button.
   * @see #setVGapScaleFactor(double)
   * @see #setGapScaleFactor(double)
   * @see #getHGapScaleFactor()
   */
  public double getVGapScaleFactor() {
    return this.vgapScaleFactor;
  }

  /**
   * Programmatically perform an action "click". This does the same thing as
   * if the user had pressed and released the action area of the button.
   */
  public void doActionClick() {
    Dimension size = getSize();
    ButtonModel actionModel = this.getActionModel();
    actionModel.setArmed(true);
    actionModel.setPressed(true);
    paintImmediately(new Rectangle(0, 0, size.width, size.height));
    try {
      Thread.sleep(100);
    } catch (InterruptedException ie) {
    }
    actionModel.setPressed(false);
    actionModel.setArmed(false);
  }

  boolean hasRichTooltips() {
    return (this.actionRichTooltip != null);
  }

  /**
   * Sets the rich tooltip for the action area of this button.
   *
   * @param richTooltip
   *            Rich tooltip for the action area of this button.
   * @see #getRichTooltip(MouseEvent)
   */
  public void setActionRichTooltip(RichTooltip richTooltip) {
    this.actionRichTooltip = richTooltip;
    RichToolTipManager richToolTipManager = RichToolTipManager
        .sharedInstance();
    if (this.hasRichTooltips()) {
      richToolTipManager.registerComponent(this);
    } else {
      richToolTipManager.unregisterComponent(this);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @seeorg.jvnet.flamingo.common.RichToolTipManager.JTrackableComponent#
   * getRichTooltip(java.awt.event.MouseEvent)
   */
  @Override
  public RichTooltip getRichTooltip(MouseEvent mouseEvent) {
    return this.actionRichTooltip;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.JComponent#setToolTipText(java.lang.String)
   */
  @Override
  public void setToolTipText(String text) {
    throw new UnsupportedOperationException("Use rich tooltip APIs");
  }

  /**
   * Returns the location order kind for buttons placed in command button
   * strips or for buttons that need the visuals of segmented strips.
   *
   * @return The location order kind for buttons placed in command button
   *         strips or for buttons that need the visuals of segmented strips.
   * @see #setLocationOrderKind(CommandButtonLocationOrderKind)
   */
  public CommandButtonLocationOrderKind getLocationOrderKind() {
    return this.locationOrderKind;
  }

  /**
   * Sets the location order kind for buttons placed in command button strips
   * or for buttons that need the visuals of segmented strips. Fires a
   * <code>locationOrderKind</code> property change event.
   *
   * @param locationOrderKind
   *            The location order kind for buttons placed in command button
   *            strips or for buttons that need the visuals of segmented
   *            strips.
   * @see #getLocationOrderKind()
   */
  public void setLocationOrderKind(
      CommandButtonLocationOrderKind locationOrderKind) {
    CommandButtonLocationOrderKind old = this.locationOrderKind;
    if (old != locationOrderKind) {
      this.locationOrderKind = locationOrderKind;
      this.firePropertyChange("locationOrderKind", old,
          this.locationOrderKind);
    }
  }

  /**
   * Returns the key tip for the action area of this button.
   *
   * @return The key tip for the action area of this button.
   * @see #setActionKeyTip(String)
   */
  public String getActionKeyTip() {
    return this.actionKeyTip;
  }

  /**
   * Sets the key tip for the action area of this button. Fires an
   * <code>actionKeyTip</code> property change event.
   *
   * @param actionKeyTip
   *            The key tip for the action area of this button.
   * @see #getActionKeyTip()
   */
  public void setActionKeyTip(String actionKeyTip) {
    String old = this.actionKeyTip;
    this.actionKeyTip = actionKeyTip;
    this.firePropertyChange("actionKeyTip", old, this.actionKeyTip);
  }
}
TOP

Related Classes of org.pushingpixels.flamingo.api.common.AbstractCommandButton$ActionHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.